/*
 * @Description: axios 二次封装
 * @Version: 2.0
 * @Autor: lhl
 * @Date: 2021-05-04 20:10:19
 * @LastEditors: lhl
 * @LastEditTime: 2021-05-05 18:04:39
 */
import axios, { AxiosRequestConfig, AxiosResponse, Method } from 'axios'
import store from '../store'
// import { Toast } from 'vant'

// 定义接口
interface PendingType {
  url?: string
  method?: Method
  params: any
  data: any
  cancel: Function
}

// 取消重复请求

const repeatRequstList: Array<PendingType> = []

// 使用 cancel token 取消请求
const CancelToken = axios.CancelToken
console.log(import.meta.env.VITE_APP_BASE_URL, 'axios')
const instance = axios.create({
  // baseURL: <string>import.meta.env.VITE_APP_BASE_URL, // 给类型 不然报错
  baseURL: import.meta.env.VITE_APP_BASE_URL as string, // 断言 不然报错
  // 指定请求超时的毫秒数(0 表示无超时时间)
  timeout: 10000,
  // 表示跨域请求时是否需要使用凭证
  withCredentials: true
})
// let loadingInstance: ElLoadingComponent

// 移除重复请求
const removePending = (config: AxiosRequestConfig) => {
  for (const key in repeatRequstList) {
    console.log(key, 'key')
    const item: number = +key
    const list: PendingType = repeatRequstList[key]
    // 当前请求在数组中存在时执行函数体
    if (
      list.url === config.url &&
      list.method === config.method &&
      JSON.stringify(list.params) === JSON.stringify(config.params) &&
      JSON.stringify(list.data) === JSON.stringify(config.data)
    ) {
      // 执行取消操作
      list.cancel('操作太频繁，请稍后再试')
      // 从数组中移除记录
      repeatRequstList.splice(item, 1)
    }
  }
}

// 添加请求拦截器
instance.interceptors.request.use(
  (config) => {
    console.log(config, '请求')
    if (config.method === 'post') {
      config.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
    }
    store.commit('showLoading')

    removePending(config)
    config.cancelToken = new CancelToken((c) => {
      repeatRequstList.push({
        url: config.url,
        method: config.method,
        params: config.params,
        data: config.data,
        cancel: c
      })
    })
    return config
  },
  (error: any) => {
    store.commit('hideLoading')
    return Promise.reject(error)
  }
)

// 添加响应拦截器
instance.interceptors.response.use(
  (response: AxiosResponse) => {
    store.commit('hideLoading')
    removePending(response.config)
    return response.data
  },
  (error: any) => {
    store.commit('hideLoading')
    const { response } = error
    // 根据返回的 http 状态码做不同的处理 ?.语法需要最新的谷歌浏览器才支持目前
    // switch (response?.status) {
    //   case 401:
    //     // token失效
    //     break
    //   case 403:
    //     // 没有权限
    //     break
    //   case 404:
    //     // 请求的资源不存在
    //     break
    //   case 500:
    //     // 服务端错误
    //     Toast('提示内容')
    //     break
    //   default:
    //     break
    // }

    // 超时重新请求
    const config = error.config
    // 全局的请求次数,请求的间隙
    const [RETRY_COUNT, RETRY_DELAY] = [3, 1000]

    if (config && RETRY_COUNT) {
      // 设置用于跟踪重试计数的变量
      config.__retryCount = config.__retryCount || 0
      // 检查是否已经把重试的总数用完
      if (config.__retryCount >= RETRY_COUNT) {
        return Promise.reject(response || { message: error.message })
      }
      // 增加重试计数
      config.__retryCount++

      // 创造新的Promise来处理指数后退
      // 在typescript中定义promise返回类型 首先要在tsconfig.json中配置ES2015.promise的lib 不然ts无法支持promise
      const backClose = new Promise((resolve) => {
        setTimeout(() => {
          // 写上 null or undefined 不然ts下面会报错
          resolve(null)
        }, RETRY_DELAY || 1)
      })

      // instance重试请求的Promise
      return backClose.then(() => {
        return instance(config)
      })
    }

    // eslint-disable-next-line
    return Promise.reject(response || { message: error.message })
  }
)

export default instance
